﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using CILADA.Core.Analysis;
using System.IO;
using CILADA.Core.Graph;
using QuickGraph;

namespace CILADA.Core
{
    public class AnalysisRunner
    {
        public void AnalyseAssemblies(IDictionary<string, string> assemblyNamesAndPaths, AnalysisModes analysisMode, string outputFile)
        {
            // build a list of assembly directories
            List<string> assemblyDirectories = new List<string>();
            foreach (string assem in assemblyNamesAndPaths.Values)
            {
                string assemDir = Path.GetDirectoryName(assem);
                if (Directory.Exists(assemDir))
                {
                    assemblyDirectories.Add(assemDir);
                }
            }

            if (!AddDirsToMonoCecilGlobalAssemblyResolver(assemblyDirectories))
            {
                Console.WriteLine("Could not add assembly dirs to the Mono.Cecil GlobalAssemblyResolver. This may cause errors.");
            }

            DependencyGraphBuilder dgb = new DependencyGraphBuilder(analysisMode);

            // foreach assembly
            foreach (KeyValuePair<string, string> e in assemblyNamesAndPaths)
            {
                try
                {
                    AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(e.Value);
                    dgb.AnalyseAssembly(assembly, e.Key);
                }
                catch (Exception ex)
                {
                    // log error and tell user that the given assembly wasnt analysed.
                }
            }

            RemoveDirsFromMonoCecilGlobalAssemblyResolver(assemblyDirectories);

            try
            {
                dgb.AssemblyGraph.SaveGraphAsGraphML(outputFile);
            }
            catch (Exception ex)
            {
                // TODO
            }
        }

        private bool AddDirsToMonoCecilGlobalAssemblyResolver(IEnumerable<string> assemblyDirectories)
        {
            // add paths to global assembly resolver

            bool isDAR = GlobalAssemblyResolver.Instance is DefaultAssemblyResolver;
            if (!isDAR) return false;

            DefaultAssemblyResolver globalResolver = (DefaultAssemblyResolver)GlobalAssemblyResolver.Instance;
            foreach (string dir in assemblyDirectories)
            {
                globalResolver.AddSearchDirectory(dir);
            }

            return true;
        }

        private bool RemoveDirsFromMonoCecilGlobalAssemblyResolver(IEnumerable<string> assemblyDirectories)
        {
            // add paths to global assembly resolver

            bool isDAR = GlobalAssemblyResolver.Instance is DefaultAssemblyResolver;
            if (!isDAR) return false;

            DefaultAssemblyResolver globalResolver = (DefaultAssemblyResolver)GlobalAssemblyResolver.Instance;
            foreach (string dir in assemblyDirectories)
            {
                globalResolver.RemoveSearchDirectory(dir);
            }

            return true;
        }
    }
}
